#ifndef QUERY_H
#define QUERY_H

#include "TextQuery.h"
#include <string>
/**
 * @brief 
 * 
 */
class Query_base
{
    friend class Query;
protected:
    using line_no = TextQuery::line_no; // 用于 eval函数 
    virtual ~Query_base() = default;
private:
    // eval 返回与当前 Query 匹配的 QueryResult
    virtual QueryResult eval(const TextQuery&) const = 0;
    // rep 是表示查询的一个 string
    virtual std::string rep() const = 0; 
};
/**
 * @brief 
 * 
 */
class Query
{
    // 这些运算符需要访问接受 shared_ptr 的构造函数，而该函数是私有的
    friend Query operator~(const Query &);
    friend Query operator|(const Query &, const Query &);
    friend Query operator&(const Query &, const Query &);
private:
    std::shared_ptr<Query_base> q;
    Query(std::shared_ptr<Query_base> query) 
        : q(query) { }
public:
    Query(const std::string&); // 构建一个新的 WordQuery
    // 接口函数：调用敌营的 Query_base操作
    QueryResult eval(const TextQuery &t) const
        { return q->eval(t); }
    std::string rep() const
        { return q->rep(); } 
    ~Query();
};
std::ostream & operator<< (std::ostream &os, const Query &query);
/**
 * @brief 
 * 
 */
class WordQuery : public Query_base
{
    friend class Query; // Query 使用 WordQuery 构造函数
    WordQuery(const std::string &s)
        : query_word(s) { }
    // 具体的类: WordQuery 将定义所有继承而来的纯虚函数
    QueryResult eval(const TextQuery &t) const
        { return t.query(query_word); }
    std::string rep() const
        { return query_word; }
    std::string query_word; // 要查找的单词  
};
inline Query::Query(const std::string &s)
    : q(new WordQuery(s)) { }
/**
 * @brief 
 * 
 */
class NotQuery : public Query_base
{
    friend Query operator~(const Query &);
    NotQuery(const Query &q)
        :   query(q) { }
    std::string rep() const 
        { return "~(" + query.rep() + ")"; }
    QueryResult eval(const TextQuery&) const;
    Query query;
};
inline Query operator~(const Query &operand)
{
    return std::shared_ptr<Query_base>(new NotQuery(operand));
}
/**
 * @brief 
 * 
 */
class BinaryQuery : public Query_base
{
protected:
    Query lhs, rhs; // 左侧和右侧运算对象
    std::string opSym; // 运算符的名字
    BinaryQuery(const Query &l, const Query &r, std::string s)
        : lhs(l), rhs(r), opSym(s) { }
    std::string rep() const 
        { return "(" + lhs.rep() + " " + opSym + " " + rhs.rep() + ")"; }
};
/**
 * @brief 
 * 
 */
class AndQuery : public BinaryQuery
{
    friend Query operator& (const Query&, const Query&);
    AndQuery(const Query &left, const Query &right)
        : BinaryQuery(left, right, "&") { }
    QueryResult eval(const TextQuery&) const;
};
inline Query operator& (const Query &lhs, const Query &rhs)
{
    return std::shared_ptr<Query_base>(new AndQuery(lhs, rhs));
}
/**
 * @brief 
 * 
 */
class OrQuery : public BinaryQuery
{
    friend Query operator| (const Query&, const Query&);
    OrQuery(const Query &left, const Query &right)
        : BinaryQuery(left, right, "|") { }
    QueryResult eval(const TextQuery&) const;
};
inline Query operator| (const Query &lhs, const Query &rhs)
{
    return std::shared_ptr<Query_base>(new OrQuery(lhs, rhs));
}
#endif